home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / termutil.0 / termutil / termutils-2.0 / tabs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-30  |  17.3 KB  |  805 lines

  1. /* tabs -- set terminal tabs
  2.    Copyright (C) 1995 Free Software Foundation, Inc.
  3.  
  4.    This program is free software; you can redistribute it and/or modify
  5.    it under the terms of the GNU General Public License as published by
  6.    the Free Software Foundation; either version 2, or (at your option)
  7.    any later version.
  8.  
  9.    This program is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details.
  13.  
  14.    You should have received a copy of the GNU General Public License
  15.    along with this program; if not, write to the Free Software
  16.    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
  17.  
  18. /* Usage: tabs [-T termtype] [-V] [-h] tabspec
  19.  
  20.    Options:
  21.  
  22.    -T termtype
  23.    --terminal=termtype    Override $TERM.
  24.  
  25.    -V
  26.    --version        Display version.
  27.  
  28.    -h
  29.    --help        Help.
  30.  
  31.    GNU tabs accepts the following types of tab specification:
  32.  
  33.    n1,n2,...
  34.            Set the TAB stops at positions n1, n2, and so on.
  35.  
  36.    -n      Set the TAB stops at intervals of n columns.
  37.        If n is zero, then all the TAB stops are cleared.
  38.  
  39.    -code
  40.    -C code
  41.    --code=code
  42.            Set the TAB stops according to the canned TAB
  43.            setting specified by code.  See fspec.def for
  44.        supported canned set of TAB stops.
  45.        The second form can be used if the code conflicts
  46.        with long options supported by GNU tabs.
  47.  
  48.    --filename
  49.    -F filename
  50.    --file=filename
  51.        Read the first line of the file specified by filename,
  52.        searching  for  a format specification.
  53.        Format specification is a blank separated sequence
  54.        of parameters and surrounded by <: and :>.
  55.        If this line contains a format specification,
  56.        set the TAB stops accordingly, otherwise
  57.        set them to every 8 columns.
  58.        The first form of this tabspec is a SYSVish way of
  59.        specifying a file.
  60.        The second form can be used if the filename conflicts
  61.        with long options supported by GNU tabs.
  62.  
  63.    GNU tabs uses the GNU termcap library.
  64.  
  65.    Junio Hamano <junio@twinsun.com> */
  66.  
  67. #include <config.h>
  68.  
  69. #if STDC_HEADERS
  70. # include <stdlib.h>
  71. #else
  72. char *getenv ();
  73. #endif
  74.  
  75. #include <stdio.h>
  76. #include <termcap.h>
  77. #include <errno.h>
  78.  
  79. #if STDC_HEADERS || HAVE_STRING_H
  80. # include <string.h>
  81. #else
  82. # include <strings.h>
  83. # define strchr index
  84. #endif
  85.  
  86. #if HAVE_UNISTD_H
  87. # include <unistd.h>
  88. #endif
  89.  
  90. #include <tcutil.h>
  91. #include <tabs.h>
  92.  
  93. #ifndef errno
  94. extern int errno;
  95. #endif
  96.  
  97. /* Number of elements in an array */
  98. #define elemof(array) (sizeof (array) / sizeof (array[0]))
  99.  
  100. char *fgetline ();
  101. void error ();
  102.  
  103. extern char *version_string;
  104.  
  105. /* Program name.  Used to report errors and usage */
  106. char *program_name;
  107.  
  108. /* Width of the terminal */
  109. static int term_width;
  110.  
  111. /* Convert a digit string to a positive integer.
  112.    A character other than terminating NUL can be
  113.    specified by stop.
  114.    On return, next points to the next character
  115.    to be scanned.
  116.    Return negative if the string contains anything
  117.    other than digits. */
  118.  
  119. static int
  120. a_to_i (spec, next, stop)
  121.      const char *spec;
  122.      const char **next;
  123.      int stop;
  124. {
  125.   int acc;
  126.  
  127.   acc = 0;
  128.   while (*spec && *spec != stop)
  129.     {
  130.       if (*spec >= '0' && *spec <= '9')
  131.     acc = acc * 10 + *spec++ - '0';
  132.       else
  133.     {
  134.       if (next)
  135.         *next = spec;
  136.       return (-1);
  137.     }
  138.     }
  139.   if (next)
  140.     if (*spec)
  141.       *next = spec + 1;
  142.     else
  143.       *next = spec;
  144.   return acc;
  145. }
  146.  
  147. /* Parse an fspec line for a tabspec.  Return a pointer
  148.    to the parameter character of spec if found and
  149.    null terminate the spec.  Return 0 otherwise.
  150.    Return the pointer used to scan the next item
  151.    in *next, if returning non-null.
  152.  
  153.    A fspec line has a sequence of parameters separated
  154.    by blanks and surrounded by <: and :>.  The parameters
  155.    are
  156.     tn1,n2,n3,...
  157.     t-n
  158.     t-code
  159.     ssize
  160.     mmargin
  161.     d
  162.     e
  163.    though we are interested in only the first three cases.
  164.  */
  165.  
  166. static char *
  167. parse_fspec_line (line, first, next)
  168.      char *line;
  169.      int first;
  170.      char **next;
  171. {
  172.   char *cp;
  173.   int terminated;
  174.  
  175.   if (first)
  176.     {
  177.       /* If this is the first time, we have to find
  178.      the beginning of the fspec bracketed by '<:' */
  179.  
  180.       while (*line)
  181.     if (line[0] == '<' && line[1] == ':')
  182.       break;
  183.     else
  184.       line++;
  185.       if (*line == 0)
  186.     return 0;
  187.       line += 2;
  188.     }
  189.   do
  190.     {
  191.       /* Skip leading blanks */
  192.       while (*line && (*line == ' ' || *line == '\t'))
  193.     line++;
  194.       /* End of line or ':>' means the end of an fspec */
  195.       if (*line == 0 ||
  196.       (*line == ':' && (line[1] == '>' || line[1] == 0)))
  197.     return 0;
  198.       switch (*line)
  199.     {
  200.     case 'e':
  201.     case 'd':
  202.     case 'm':
  203.     case 's':
  204.     case 't':
  205.       /* We seem to have found what we are looking for.
  206.          Let's make sure we have closing bracket before
  207.          returning.  Also, null terminate what we have
  208.          just found. */
  209.       terminated = 0;
  210.       for (cp = line; *cp; cp++)
  211.         if (*cp == ':' && cp[1] == '>')
  212.           {
  213.         /* Ok, indeed there is a closing bracket.
  214.            In case the spec was the last item in the list
  215.            and there wasn't any blanks left (i.e. "<:... tspec:>"),
  216.            let's null terminate it here, too. */
  217.         if (!terminated)
  218.           {
  219.             *cp = 0;
  220.             *next = 0;
  221.           }
  222.         return line;
  223.           }
  224.         else if (!terminated && (*cp == ' ' || *cp == '\t'))
  225.           {
  226.         *cp = 0;
  227.         *next = cp + 1;
  228.         terminated = 1;
  229.           }
  230.       break;
  231.     default:
  232.       /* Skip to next blank */
  233.       while (*line && *line != ' ' && *line != '\t' &&
  234.          !(*line == ':' && line[1] == '>'))
  235.         line++;
  236.       if (*line != ' ' && *line != '\t')
  237.         return 0;
  238.     }
  239.     }
  240.   while (1);
  241. }
  242.  
  243. static void
  244. usage (stream, status)
  245.      FILE *stream;
  246.      int status;
  247. {
  248.   static char *specs[] =
  249.   {
  250.     "n1,n2,...   : Set TAB stops at positions n1,n2,...",
  251.     "-number     : Set TAB stops every number columns",
  252.     "-C code     : Set TAB stops using canned settings",
  253.     "-code       : Set TAB stops using canned settings",
  254.     "-F filename : Set TAB stops according to the first line of the file",
  255.     "--filename  : Set TAB stops according to the first line of the file",
  256.     0,
  257.   };
  258.   char **p;
  259.   struct fspec_table *fstp;
  260.   int ix;
  261.  
  262.   fprintf (stream, "Usage: %s [-T termtype] [--terminal=termtype] tabspec\n",
  263.        program_name);
  264.   for (p = specs; *p; p++)
  265.     fprintf (stream, "  %s\n", *p);
  266.   fprintf (stream, "Canned settings are:\n");
  267.   for (fstp = fspec_table; fstp->code; fstp++)
  268.     {
  269.       fprintf (stream, "-%s\t", fstp->code);
  270.       for (ix = 0; fstp->tabs[ix] != 0; ix++)
  271.     fprintf (stream, "%d ", fstp->tabs[ix]);
  272.       fprintf (stream, "(%s)\n", fstp->description);
  273.     }
  274.   exit (status);
  275. }
  276.  
  277. /* Parse a tabspec and fill them into tabs array.  Return
  278.    number of tab stops filled in.  Return negative on
  279.    error. */
  280.  
  281. static int
  282. parse_tabspec (spec, tabs, tabs_length)
  283.      const char *spec;
  284.      int *tabs;
  285.      int tabs_length;
  286. {
  287.   const char *ispec;
  288.   int tab, ix, width;
  289.  
  290.   ispec = spec;
  291.  
  292.   if (spec[0] != '-')
  293.     {
  294.       /* Has to be list of numbers */
  295.       for (ix = 0;
  296.        ix < tabs_length && spec[0] != 0;
  297.        ix++)
  298.     {
  299.       if (spec[0] == '+')
  300.         {
  301.           /* An increment */
  302.           if (ix == 0)
  303.         goto bogus;
  304.           tab = a_to_i (spec + 1, &spec, ',');
  305.           if (tab <= 0)
  306.         goto bogus;
  307.           tab = tabs[ix - 1] + tab;
  308.         }
  309.       else
  310.         tab = a_to_i (spec, &spec, ',');
  311.       if (tab <= 0 || (ix > 0 && tab < tabs[ix - 1]))
  312.         goto bogus;
  313.       tabs[ix] = tab;
  314.     }
  315.       return ix;
  316.     }
  317.   else
  318.     {
  319.       if (spec[1] >= '0' && spec[1] <= '9')
  320.     {
  321.       /* Every N column */
  322.       width = a_to_i (&spec[1], spec, 0);
  323.       if (width < 0)
  324.         goto bogus;
  325.       else if (width == 0)
  326.         return 0;
  327.       else
  328.         {
  329.           for (tab = 1, ix = 0;
  330.            ix < tabs_length && tab <= term_width;
  331.            tab += width, ix++)
  332.         tabs[ix] = tab;
  333.           return ix;
  334.         }
  335.     }
  336.       else
  337.     {
  338.       /* Use canned tabs list */
  339.       for (tab = 0; fspec_table[tab].code != 0; tab++)
  340.         if (strcmp (fspec_table[tab].code, &spec[1]) == 0)
  341.           break;
  342.       if (fspec_table[tab].code != 0)
  343.         {
  344.           for (ix = 0;
  345.            ix < tabs_length;
  346.            ix++)
  347.         {
  348.           tabs[ix] = fspec_table[tab].tabs[ix];
  349.           if (tabs[ix] <= 0)
  350.             break;
  351.         }
  352.           return ix;
  353.         }
  354.       else
  355.         goto bogus;
  356.     }
  357.     }
  358. bogus:
  359.   error (0, 0, "invalid tab specification `%s'", ispec);
  360.   usage (stderr, 1);
  361. }
  362.  
  363. static int
  364. tcputchar (c)
  365.      char c;
  366. {
  367.   putchar (c);
  368.   return c;
  369. }
  370.  
  371. /* Set TAB stops.
  372.    numtabs == 0 means clear all tabs */
  373.  
  374. static void
  375. set_tabstops (term, tabs, numtabs)
  376.      char *term;
  377.      int *tabs;
  378.      int numtabs;
  379. {
  380.   char *cr, *ct, *st;
  381.   int lines, tab, ix, col;
  382.   char *noclear =
  383.   "cannot clear tabs on terminal %s";
  384.   char *noset =
  385.   "cannot set nonstandard hardware tabs on terminal %s";
  386.  
  387.   ct = tgetstr ("ct", 0);
  388.   lines = tgetnum ("li");
  389.   if (lines < 0)
  390.     lines = 25;            /* Should be a reasonable default */
  391.  
  392.   if (numtabs == 0)
  393.     {
  394.       if (ct == 0)
  395.     error (1, 0, noclear, term);
  396.     }
  397.   else
  398.     {
  399.       /* If both ct and st are not present, we are in trouble */
  400.       if ((ct == 0) ||
  401.       (st = tgetstr ("st", 0)) == 0)
  402.     {
  403.       /* If we are setting tabs to every 8 columns, then
  404.          we might be ok. */
  405.       for (tab = 1, ix = 0; ix < numtabs; ix++, tab += 8)
  406.         {
  407.           if (tabs[ix] != tab)
  408.         error (1, 0, noset, term);
  409.         }
  410.       /* Return without doing anything; hope it's ok */
  411.       return;
  412.     }
  413.     }
  414.  
  415.   cr = tgetstr ("cr", 0);
  416.   if (cr == 0)
  417.     cr = "\r";
  418.  
  419.   /* Disable OPOST */
  420.   translations_off ();
  421.  
  422.   tputs (cr, lines, tcputchar);    /* Bring cursor to column 1 */
  423.   tputs (ct, lines, tcputchar);    /* Clear tabs */
  424.   tputs (cr, lines, tcputchar);    /* Bring cursor to column 1 */
  425.  
  426.   if (numtabs)
  427.     {
  428.       for (ix = 0, col = 1;
  429.        ix < numtabs && col <= term_width;
  430.        ix++)
  431.     {
  432.       while (tabs[ix] > col && col <= term_width)
  433.         {
  434.           putchar (' ');
  435.           col++;
  436.         }
  437.       tputs (st, 1, tcputchar);
  438.     }
  439.       tputs (cr, lines, tcputchar);
  440.     }
  441.   fflush (stdout);
  442.  
  443.   /* Enable OPOST */
  444.   restore_translations ();
  445.  
  446.   /* Disable XTABS */
  447.   disable_xtabs ();
  448. }
  449.  
  450. /* Read the termcap entry for term and get the width
  451.    of terminal. */
  452.  
  453. static void
  454. prepare_termcap (term)
  455.      char *term;
  456. {
  457.   char *tc_pc;
  458.  
  459.   if (term == NULL)
  460.     error (1, 0, "No value for $TERM and no -T specified");
  461.   switch (tgetent (0, term))
  462.     {
  463.     case 0:
  464.       error (1, 0, "Unknown terminal type `%s'", term);
  465.     case (-1):
  466.       error (1, 0, "No termcap database");
  467.     }
  468.   tc_pc = tgetstr ("pc", 0);
  469.   PC = tc_pc ? *tc_pc : 0;
  470.   /* It leaks, but who cares */
  471.   term_width = tgetnum ("co");
  472.   if (term_width <= 0)
  473.     term_width = 80;        /* Should be a reasonable default */
  474. }
  475.  
  476. void
  477. version ()
  478. {
  479.   printf ("GNU tabs version %s\n", version_string);
  480.   exit (0);
  481. }
  482.  
  483. static char *optval;
  484.  
  485. enum tabs_args
  486.   {
  487.     arg_termtype, arg_help, arg_version,
  488.     arg_canned_tabs, arg_file,
  489.     arg_every_n_column,
  490.     arg_tablist, arg_bad
  491.   };
  492.  
  493. /* Some of the SYSVish tabspecs look like short or long
  494.    options, and even GNU getopt doesn't help us very much.
  495.    This function parses each argument and returns what
  496.    kind of option it is.  If the option takes an argument,
  497.    optval either points to the argument, or NULL, in
  498.    which case the argument is the next element in av[] */
  499.  
  500. static enum tabs_args
  501. parse_an_arg (arg)
  502.      char *arg;
  503. {
  504.   int arglen;
  505.  
  506.   switch (arg[0])
  507.     {
  508.     case '-':
  509.       switch (arg[1])
  510.     {
  511.     case 'T':        /* short opt 'T' -- terminal */
  512.       if (arg[2])
  513.         optval = &arg[2];
  514.       else
  515.         optval = 0;
  516.       return arg_termtype;
  517.     case '-':
  518.       /* longopt --terminal, --help, --version, --file,
  519.          or SYSVish --filename. */
  520.       switch (arg[2])
  521.         {
  522.         case 't':        /* --terminal? */
  523.         case 'h':        /* --help? */
  524.         case 'v':        /* --version? */
  525.         case 'f':        /* --file? */
  526.         case 'c':        /* --code? */
  527.           optval = strchr (&arg[3], '=');
  528.           if (optval)
  529.         {
  530.           *optval++ = 0;
  531.           if (strncmp (&arg[2], "terminal", optval - &arg[3]) == 0)
  532.             return arg_termtype;
  533.           else if (strncmp (&arg[2], "file", optval - &arg[3]) == 0)
  534.             return arg_file;
  535.           else if (strncmp (&arg[2], "code", optval - &arg[3]) == 0)
  536.             return arg_canned_tabs;
  537.           /* --version and --help doesn't take any argument.
  538.              This must be a SYSVish --filename with a funny
  539.              filename that has an equal sign in it. */
  540.           optval[-1] = '=';
  541.         }
  542.           else
  543.         {
  544.           /* Since there is no equal sign, option argument (if any)
  545.              is the next argument */
  546.           optval = 0;
  547.           arglen = strlen (&arg[2]);
  548.  
  549.           if (strncmp (&arg[2], "terminal", arglen) == 0)
  550.             return arg_termtype;
  551.           else if (strncmp (&arg[2], "file", arglen) == 0)
  552.             return arg_file;
  553.           else if (strncmp (&arg[2], "code", arglen) == 0)
  554.             return arg_canned_tabs;
  555.           else if (strncmp (&arg[2], "version", arglen) == 0)
  556.             return arg_version;
  557.           else if (strncmp (&arg[2], "help", arglen) == 0)
  558.             return arg_help;
  559.           /* Otherwise, this is SYSVish --filename */
  560.         }
  561.           /* fall through */
  562.         default:        /* SYSVish --filename */
  563.           optval = &arg[2];
  564.           return arg_file;
  565.         }
  566.       break;
  567.     case 'F':        /* short opt 'F' - file */
  568.       if (arg[2])
  569.         optval = &arg[2];
  570.       else
  571.         optval = 0;
  572.       return arg_file;
  573.     case 'C':        /* short opt 'C' - code */
  574.       if (arg[2])
  575.         optval = &arg[2];
  576.       else
  577.         optval = 0;
  578.       return arg_canned_tabs;
  579.     case 'h':        /* short opt 'h' - help */
  580.       return arg_help;
  581.     case 'V':        /* short opt 'V' - version */
  582.       return arg_version;
  583.     case '0':
  584.     case '1':
  585.     case '2':
  586.     case '3':
  587.     case '4':
  588.     case '5':
  589.     case '6':
  590.     case '7':
  591.     case '8':
  592.     case '9':
  593.       {
  594.         char *cp;
  595.         int bad;
  596.  
  597.         for (bad = 0, cp = &arg[1]; *cp; cp++)
  598.           if (!(*cp >= '0' && *cp <= '9'))
  599.         {
  600.           bad++;
  601.           break;
  602.         }
  603.         if (bad == 0)
  604.           {
  605.         optval = &arg[1];
  606.         return arg_every_n_column;
  607.           }
  608.       }
  609.       /* fall through - this is SYSVish canned code
  610.          that begins with a digit (GNU tabs
  611.          currently doesn't define any canned code
  612.          that begins with a digit, though.) */
  613.     default:        /* canned code */
  614.       optval = &arg[1];
  615.       return arg_canned_tabs;
  616.     }
  617.     case '0':
  618.     case '1':
  619.     case '2':
  620.     case '3':
  621.     case '4':
  622.     case '5':
  623.     case '6':
  624.     case '7':
  625.     case '8':
  626.     case '9':
  627.       optval = arg;
  628.       return arg_tablist;
  629.     default:
  630.       return arg_bad;
  631.     }
  632. }
  633.  
  634. int
  635. main (argc, argv)
  636.      int argc;
  637.      char **argv;
  638. {
  639.   int *tabs;
  640.   int every;
  641.   int numtabs;
  642.   int opt;
  643.   char *tabspec;
  644.   enum
  645.     {
  646.       spec_normal, spec_every, spec_file
  647.     } tabspec_type;
  648.   char *nonunique = "More than one tabspec specified";
  649.   char *term;
  650.   /* 1003.2 specifies the format of this message.  */
  651.   char *required = "option requires an argument -- %c";
  652.  
  653.   program_name = argv[0];
  654.   term = getenv ("TERM");
  655.   tabs = 0;
  656.   tabspec = 0;
  657.  
  658.   for (opt = 1; opt < argc; opt++)
  659.     {
  660.       switch (parse_an_arg (argv[opt]))
  661.     {
  662.     case arg_termtype:
  663.       if (optval)
  664.         term = optval;
  665.       else if (opt == argc - 1)
  666.         error (1, 0, required, 'T');
  667.       else
  668.         term = argv[++opt];
  669.       break;
  670.     case arg_help:
  671.       usage (stdout, 0);
  672.     case arg_version:
  673.       version ();
  674.     case arg_every_n_column:
  675.       if (tabspec)
  676.         error (1, 0, nonunique);
  677.       tabspec = optval;
  678.       tabspec_type = spec_every;
  679.       break;
  680.     case arg_canned_tabs:
  681.     case arg_tablist:
  682.       if (tabspec)
  683.         error (1, 0, nonunique);
  684.       if (optval)
  685.         tabspec = optval;
  686.       else if (opt == argc - 1)
  687.         error (1, 0, required, 'C');
  688.       else
  689.         tabspec = argv[++opt];
  690.       tabspec_type = spec_normal;
  691.       break;
  692.     case arg_file:
  693.       if (tabspec)
  694.         error (1, 0, nonunique);
  695.       if (optval)
  696.         tabspec = optval;
  697.       else if (opt == argc - 1)
  698.         error (1, 0, required, 'f');
  699.       else
  700.         tabspec = argv[++opt];
  701.       tabspec_type = spec_file;
  702.       break;
  703.     case arg_bad:
  704.     default:
  705.       usage (stderr, 1);
  706.     }
  707.     }
  708.  
  709.   if (tabspec == 0)
  710.     /* No tabspec specified */
  711.     usage (stderr, 1);
  712.  
  713.   if ((term == 0) || (term[0] == 0))
  714.     /* POSIX tells us to output TAB setting sequence for
  715.        ``unspecified default terminal type'' in this case
  716.        instead of reporting an error.
  717.        We decided that TAB means very very little on our
  718.        default terminal. ;-) */
  719.     exit (0);
  720.  
  721.   prepare_termcap (term);
  722.  
  723.   /* At most term_width TAB stops can be set for
  724.      a terminal of width term_width */
  725.   tabs = (int *) xmalloc (sizeof (int) * term_width);
  726.  
  727.   switch (tabspec_type)
  728.     {
  729.     case spec_every:
  730.       /* parse_an_arg has already verified that
  731.      tabspec is a digits-only string */
  732.       every = a_to_i (tabspec, 0, 0);
  733.     every_n_column:
  734.       if (every == 0)
  735.     /* Clearing tabs */
  736.     numtabs = 0;
  737.       else
  738.     {
  739.       int col, ix;
  740.       numtabs = term_width / every;
  741.       for (ix = 0, col = 1;
  742.            col <= term_width;
  743.            ix++, col += every)
  744.         tabs[ix] = col;
  745.     }
  746.       break;
  747.     case spec_file:
  748.       {
  749.     /* Read the first line of the file */
  750.     FILE *fp;
  751.     char *line;
  752.     fp = fopen (tabspec, "r");
  753.     if (!fp)
  754.       {
  755.         error (0, errno, "cannot open `%s'", tabspec);
  756.         return (-1);
  757.       }
  758.  
  759.     line = fgetline (fp);
  760.     fclose (fp);
  761.  
  762.     /* SYSVish --filename resets TAB stops to every 8
  763.        columns, if an fspec line is not found */
  764.     if (line == 0)
  765.       {
  766.         every = 8;
  767.         goto every_n_column;
  768.       }
  769.     else
  770.       {
  771.         int first;
  772.         char *next;
  773.  
  774.         first = 1;
  775.         tabspec = line;
  776.         while ((tabspec = parse_fspec_line (tabspec, first, &next)) != 0)
  777.           {
  778.         first = 0;
  779.         if (*tabspec == 't')
  780.           {
  781.             numtabs = parse_tabspec (tabspec + 1, tabs, term_width);
  782.             free (line);
  783.             goto set_tabs;
  784.           }
  785.         else
  786.           tabspec = next;
  787.           }
  788.         free (line);
  789.         /* There was no specification.  Set it to default. */
  790.         every = 8;
  791.         goto every_n_column;
  792.       }
  793.       }
  794.       break;
  795.     default:
  796.       numtabs = parse_tabspec (tabspec, tabs, term_width);
  797.       if (numtabs < 0)
  798.     usage (stderr, 1);
  799.       break;
  800.     }
  801. set_tabs:
  802.   set_tabstops (term, tabs, numtabs);
  803.   exit (0);
  804. }
  805.